package com.sixbing.android.topstatebar.util;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.os.SystemProperties;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.util.TypedValue;

import java.lang.reflect.Method;

/**
 * desc :NotchScreen
 * user : sixbing
 * time : 2019-08-02 17:00.
 * version : 1.0
 */
public class NotchScreenUtil {

    private final static int DEVICE_BRAND_OPPO = 0x0001;//OPPO
    private final static int DEVICE_BRAND_HUAWEI = 0x0002;//Huawei
    private final static int DEVICE_BRAND_VIVO = 0x0003;//VIVO
    private final static int DEVICE_BRAND_XIAOMI = 0x0004;//XIAOMI
    private final static int DEVICE_BRAND_Meizu = 0x0005;//Meizu
    private final static int DEVICE_BRAND_samsung = 0x0006;//samsung
    private final static int DEVICE_BRAND_Lenovo = 0x0007;//Lenovo
    private final static int DEVICE_BRAND_zte = 0x0008;//zte
    private final static int DEVICE_BRAND_generic = 0x0009;//generic
    private final static int DEVICE_BRAND_yijia = 0x000a;//
    private final static int DEVICE_BRAND_chuizi = 0x000b;//

    /**
     * <p>
     * StatusHeight
     * </p>
     *
     * @param context context
     * @return int
     */
    public static int getStatusHeight(Context context) {
        int statusHeight;
        if (Build.VERSION.SDK_INT >= 26) {//Notch Height
            statusHeight = getNotchScreenHeight(context);
        } else if (Build.VERSION.SDK_INT >= 19) {//no Notch Height
            Resources resources = context.getResources();
            int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
            statusHeight = resources.getDimensionPixelSize(resourceId);
        } else {
            statusHeight = 0;
        }
        return statusHeight;
    }

    /**
     *get Notch Height
     *
     * @param context context
     * @return Notch Height
     */
    public static int getNotchScreenHeight(Context context) {
        return getNotchScreenHeight(context, 85);
    }

    /**
     * get Notch Height
     *
     * @param context   context
     * @param defaultPx defaultPx
     * @return Notch Height
     */
    public static int getNotchScreenHeight(Context context, int defaultPx) {
        int height = defaultPx;
        int deviceType = getDeviceBrand();
        switch (deviceType) {
            case DEVICE_BRAND_OPPO:
                height = getNotchSizeAtOppo(context);
                break;
            case DEVICE_BRAND_VIVO:
                height = getNotchSizeAtVivo(context);
                break;
            case DEVICE_BRAND_HUAWEI:
                height = getNotchSizeAtHuawei(context);
                break;
            case DEVICE_BRAND_XIAOMI:
                if (Build.VERSION.SDK_INT == 26) {
                    height = getNotchHeightXiaoMiO(context);
                } else if (Build.VERSION.SDK_INT > 26) {
                    height = getNotchHeightXiaoMiP(context);
                }
                break;
        }
        return height;
    }

    /**
     * get phone brand
     * http://shunji.wang/852.html, brand list
     *
     * @return phone brand
     */
    @SuppressLint("DefaultLocale")
    private static int getDeviceBrand() {
        String brand = Build.BRAND.trim().toUpperCase();
        if (brand.contains("HUAWEI")) {
            Log.d("device brand", "HUAWEI");
            return DEVICE_BRAND_HUAWEI;
        } else if (brand.contains("OPPO")) {
            Log.d("device brand", "OPPO");
            return DEVICE_BRAND_OPPO;
        } else if (brand.contains("VIVO")) {
            Log.d("device brand", "VIVO");
            return DEVICE_BRAND_VIVO;
        } else if (brand.contains("Xiaomi")) {
            Log.d("device brand", "Xiaomi");
            return DEVICE_BRAND_XIAOMI;
        }
        return 0;
    }

    /**
     * Mi start
     *
     * @param context context
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private static int getNotchHeightXiaoMiO(Context context) {
        if (!hasNotchInMi()) {
            return 0;
        }
        int result = 85;
        if (context == null) {
            return 85;
        }
        int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
        if (resourceId > 0) {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

    /**
     * Mi start
     *
     * @param context context
     */
    @RequiresApi(api = 27)
    private static int getNotchHeightXiaoMiP(Context context) {
        if (!hasNotchInMi()) {
            return 0;
        }
        int result = 85;
        if (context == null) {
            return 85;
        }
        int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
        if (resourceId > 0) {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

    /**
     * Mi end
     *
     * @return SystemProperties error  gradle
     * android.os.SystemProperties
     */
    private static boolean hasNotchInMi() {
        return SystemProperties.getInt("ro.miui.notch", 0) == 1;
    }

    /**
     * huwei start
     *
     */
    private static boolean hasNotchInScreenAtHuawei(Context context) {
        boolean ret = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class<?> HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            ret = (Boolean) get.invoke(HwNotchSizeUtil);
            Log.d("NotchScreenUtil", "this Huawei device has notch in screen?" + ret);
        } catch (ClassNotFoundException e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen ClassNotFoundException", e);
        } catch (NoSuchMethodException e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen NoSuchMethodException", e);
        } catch (Exception e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen Exception", e);
        }
        return ret;
    }

    /**
     * get huawei phone height
     * huawei end
     *
     * @param context context
     * @return height
     */
    private static int getNotchSizeAtHuawei(Context context) {
        if (hasNotchInScreenAtHuawei(context)) {
            int[] ret = new int[]{0, 0};
            try {
                ClassLoader cl = context.getClassLoader();
                Class<?> HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
                Method get = HwNotchSizeUtil.getMethod("getNotchSize");
                ret = (int[]) get.invoke(HwNotchSizeUtil);

            } catch (ClassNotFoundException e) {
                Log.e("NotchScreenUtil", "getNotchSize ClassNotFoundException");
            } catch (NoSuchMethodException e) {
                Log.e("NotchScreenUtil", "getNotchSize NoSuchMethodException");
            } catch (Exception e) {
                Log.e("NotchScreenUtil", "getNotchSize Exception");
            }
            return ret[1];
        }
        return 0;
    }

    /**
     * Oppo start
     * Oppo has Notch
     */
    private static boolean hasNotchInScreenAtOppo(Context context) {
        boolean hasNotch = context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
        Log.d("NotchScreenUtil", "this OPPO device has notch in screen" + hasNotch);
        return hasNotch;
    }

    /**
     * Oppo Notch height
     * Oppo end
     */
    private static int getNotchSizeAtOppo(Context context) {
        if (hasNotchInScreenAtOppo(context)) {
            return 80;
        }
        return 0;
    }

    /**
     * vivo start
     */
    private static final int NOTCH_IN_SCREEN_VOIO = 0x00000020;//

    private static boolean hasNotchInScreenAtVivo(Context context) {
        boolean ret = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class<?> FtFeature = cl.loadClass("com.util.FtFeature");
            Method get = FtFeature.getMethod("isFeatureSupport", int.class);
            ret = (Boolean) get.invoke(FtFeature, NOTCH_IN_SCREEN_VOIO);
            Log.d("NotchScreenUtil", "this VIVO device has notch in screen?" + ret);
        } catch (ClassNotFoundException e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen ClassNotFoundException", e);
        } catch (NoSuchMethodException e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen NoSuchMethodException", e);
        } catch (Exception e) {
            Log.e("NotchScreenUtil", "hasNotchInScreen Exception", e);
        }
        return ret;
    }

    /**
     * vivo end
     */
    private static int getNotchSizeAtVivo(Context context) {
        if (hasNotchInScreenAtVivo(context)) {
            return dp2px(context, 32);
        }
        return 0;
    }

    /**
     * dp to  px
     *
     * @param context context
     * @param dpValue dpValue
     * @return int
     */
    private static int dp2px(Context context, int dpValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpValue, context.getResources().getDisplayMetrics());
    }

}
